import Router from 'koa-router';
import { SysMenuService } from '../../service/system/SysMenu.js';
import {
  SysMenu,
  CreateSysMenuDto,
  UpdateSysMenuDto,
  SysMenuQueryDto,
} from '../../entities/system/SysMenu.js';
import type { AppContext } from '../../types/index.js';
import { Response } from '../../utils/response.js';
import { BusinessException } from '../../types/exceptions.js';
import { ValidationUtil } from '../../utils/validation.js';

const router = new Router<Record<string, unknown>, AppContext>();

/**
 * 菜单控制器
 * @description 使用单例模式，避免重复创建服务实例
 */
class MenuController {
  private static instance: MenuController;
  private readonly menuService: SysMenuService;

  private constructor() {
    this.menuService = new SysMenuService();
  }

  static getInstance(): MenuController {
    if (!MenuController.instance) {
      MenuController.instance = new MenuController();
    }
    return MenuController.instance;
  }

  /**
   * 创建菜单
   * @param ctx - Koa应用上下文
   */
  async create(ctx: AppContext): Promise<void> {
    const menu = ctx.request.body as CreateSysMenuDto;

    // 参数验证
    ValidationUtil.validateRequiredString(menu.name as string, '菜单名');
    if (typeof menu.type !== 'number') {
      throw new BusinessException('菜单类型必须是数字');
    }

    // 验证菜单类型范围
    if (![1, 2, 3].includes(menu.type as number)) {
      throw new BusinessException('菜单类型必须是1(目录)、2(菜单)或3(按钮)');
    }

    const menuId = await this.menuService.create(menu);
    ctx.body = Response.success('创建成功', { id: menuId });
  }

  /**
   * 获取菜单列表
   * @param ctx - Koa应用上下文
   */
  async list(ctx: AppContext): Promise<void> {
    const { page, pageSize, ...query } = ctx.query;
    const { pageNum, pageSizeNum } = ValidationUtil.validatePagination(
      page as string,
      pageSize as string
    );

    const result = await this.menuService.list(pageNum, pageSizeNum, query as SysMenuQueryDto);
    ctx.body = Response.success('获取成功', result);
  }

  /**
   * 更新菜单
   * @param ctx - Koa应用上下文
   */
  async update(ctx: AppContext): Promise<void> {
    const id = ValidationUtil.validateId(ctx.params.id, 'ID');
    const menu = ctx.request.body as UpdateSysMenuDto;

    // 验证菜单类型范围（如果提供）
    if (menu.type !== undefined && ![1, 2, 3].includes(menu.type as number)) {
      throw new BusinessException('菜单类型必须是1(目录)、2(菜单)或3(按钮)');
    }

    const success = await this.menuService.update(id, menu);
    if (!success) {
      throw new BusinessException('更新失败，菜单不存在');
    }
    ctx.body = Response.success('更新成功');
  }

  /**
   * 删除菜单
   * @param ctx - Koa应用上下文
   */
  async delete(ctx: AppContext): Promise<void> {
    const id = ValidationUtil.validateId(ctx.params.id, 'ID');

    const success = await this.menuService.delete(id);
    if (!success) {
      throw new BusinessException('删除失败，菜单不存在');
    }
    ctx.body = Response.success('删除成功');
  }

  /**
   * 根据ID获取菜单
   * @param ctx - Koa应用上下文
   */
  async getById(ctx: AppContext): Promise<void> {
    const id = ValidationUtil.validateId(ctx.params.id, 'ID');

    const menu = await this.menuService.getById(id);
    if (!menu) {
      throw new BusinessException('菜单不存在');
    }
    ctx.body = Response.success('获取成功', menu);
  }

  /**
   * 根据父菜单ID获取子菜单列表
   * @param ctx - Koa应用上下文
   */
  async getByParentId(ctx: AppContext): Promise<void> {
    const parentId = ValidationUtil.validateId(ctx.params.parentId, '父菜单ID');

    const menus = await this.menuService.getByParentId(parentId);
    ctx.body = Response.success('获取成功', menus);
  }

  /**
   * 根据权限标识获取菜单
   * @param ctx - Koa应用上下文
   */
  async getByPermission(ctx: AppContext): Promise<void> {
    const permission = ctx.params.permission as string;
    ValidationUtil.validateRequiredString(permission, '权限标识');
    const menu = await this.menuService.getByPermission(permission);
    if (!menu) {
      throw new BusinessException('菜单不存在');
    }
    ctx.body = Response.success('获取成功', menu);
  }

  /**
   * 获取菜单树结构
   * @param ctx - Koa应用上下文
   */
  async getTree(ctx: AppContext): Promise<void> {
    // 获取所有菜单
    const result = await this.menuService.list(1, 1000, { status: 0 });
    const allMenus = result.list;

    // 构建树结构
    const buildTree = (
      parentId: number = 0
    ): Array<SysMenu & { children?: Array<SysMenu & { children?: unknown }> }> => {
      return allMenus
        .filter(menu => menu.parent_id === parentId)
        .sort((a, b) => a.order - b.order)
        .map(menu => ({
          ...menu,
          children: buildTree(menu.id),
        }));
    };

    const tree = buildTree();
    ctx.body = Response.success('获取成功', tree);
  }
}

const controller = MenuController.getInstance();

/**
 * 路由定义
 */
router.post('/create', (ctx: AppContext) => controller.create(ctx));
router.get('/list', (ctx: AppContext) => controller.list(ctx));
router.put('/:id', (ctx: AppContext) => controller.update(ctx));
router.delete('/:id', (ctx: AppContext) => controller.delete(ctx));
router.get('/:id', (ctx: AppContext) => controller.getById(ctx));
router.get('/parent/:parentId', (ctx: AppContext) => controller.getByParentId(ctx));
router.get('/permission/:permission', (ctx: AppContext) => controller.getByPermission(ctx));
router.get('/tree/all', (ctx: AppContext) => controller.getTree(ctx));

export default router;
